/**
 * @file sleep2.c
 * @author liangwenhao (1943080020@qq.com)
 * @brief 
 * @version 0.1
 * @date 2021-07-30
 * 
 * @copyright Copyright (c) 2021
 * 
 * @authorGitee  https://gitee.com/liangwenhao
 * @authorGithub https://github.com/WHaoL
 * @authorBlogs https://blog.csdn.net/liangwenhao1108
 *  
 * @Code Description:   P270
 *                      确保了 不会卡死在pause()处
 *                      即使pause()从未执行，在发生SIGALRM时，sleep2函数也会正常返回
 */

#include <setjmp.h>
#include <signal.h>
#include <unistd.h>

static jmp_buf env_alrm;

static void sig_alrm_handler(int signo)
{
    longjmp(env_alrm, 1);
}

/***
 * 解决了原子操作的问题
 * 
 * 但是存在的问题依然很突出
 *      如果SIGALRM中断了 某个其他信号处理程序，则调用longjmp()会提早终止 该信号处理程序
 */
unsigned int sleep2(unsigned int seconds)
{
    if (signal(SIGALRM, sig_alrm_handler) == SIG_ERR)
        return (seconds);
    if (setjmp(env_alrm) == 0)
    {
        alarm(seconds); /* start the timer */
        pause();        /* next caught signal wakes us up */
    }
    return (alarm(0)); /* turn off timer, return unslept time */
}
